梦入琼楼寒有月,行过石树冻无烟

vue and axios

Callbacks and Asynchronous

AXIOS 正如文档中所描述的,它是一个基于 promise用于因此 的网络请求库,即异步(async) 和 同步(await) 同时也在文档中描述了一段故事:

1
2
3
4
5
6
7
8
9
想象一下,你是一位顶级歌手,粉丝没日没夜的询问你什么时候发送新歌,为了从中解放,你承诺(promise)会在单曲发布的第一时间发给他们。你给了粉丝们一个列表。他们可以在上面填写他们的电子邮件地址,以便当歌曲发布后,让所有订阅了的人能够立即收到。即便遇到不测,例如录音室发生了火灾,以致你无法发布新歌,他们也能及时收到相关通知。

每个人都很开心:你不会被任何人催促,粉丝们也不用担心错过歌曲发行。

这是我们在编程中经常遇到的事儿与真实生活的类比:


1. 生产者代码,会做一些事并且需要一定时间,例如通过网络加载数据的 code;
2. 消费者代码,想要在生产者代码完成工作的第一时间就可获得回馈(也就是工作结果),可以理解为粉丝。

而 promise 就是将上述两者连接在一起的特殊 JavaScript 对象,使得可以立即获得相关信息,这也被称之为 “异步”,因为 Promise 是 AXOPS 的基础,所以本章也会从 Promise 开始来进行学习。

在此之前我们需要了解下 Promise 对象,他主要用于表示一个异步操作最终完成的结果,当然也会包含失败的结果值。

Callbacks

又被称之为或调参数,即将一个参数传递给另一个参数的过程被称之为回调,在 JavaScript 回调 (w3schools.com) 这一章节中您可以清除的了解到 callback 的主要用法。

抛出基础问题不谈,Callbacks 主要就针对 调用 两个字来进行深入,以及将参数带入函数中进行计算,完成后回调,这里 W3 的例子是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Callbacks</h2>

<p>Do a calculation and then display the result.</p>

<p id="demo"></p>

<script>
function myDisplayer(something) {
document.getElementById("demo").innerHTML = something;
}

function myCalculator(num1, num2, myCallback) {
let sum = num1 + num2;
myCallback(sum);
}

myCalculator(5, 5, myDisplayer);
</script>

</body>
</html>

在上述的 code 中,myDisplayer 函数中的 something 参数被之后的 document…… 方法引入,之后 myCalculatornum1num2 参数通过 myCallback 回调给 sun,之后当 myCalculator 被调用时所添加的参数也会被解析到 sun 这个变量中进行计算,并将 myCalculator 函数绑定返回给 myDisplayer

Asynchronous

异步通常与 Callbacks 一起使用,同样在 w3 这一章节中所提供的例子使得我们可以快速了解 Asynchronous 和 Callbacks 一起使用的范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function myDisplayer(some) {  
document.getElementById("demo").innerHTML = some;
}

function getFile(myCallback) {
let req = new XMLHttpRequest();
req.open('GET', "mycar.html");
req.onload = function() {
if (req.status == 200) {
myCallback(this.responseText);
} else {
myCallback("Error: " + req.status);
}
}
req.send();
}

getFile(myDisplayer);

在异步的定位中,主要将与其他函数并行运行的函数为异步,结合上述的 Code 我们可以知道,getFilemyDisplayer 是同时执行的,这加快了网站加载的速度以及用户的体验。

同样是在 getFile 下的 myCallback 参数,之后该参数返回的则是当前的请求信息和错误,以至于最后如果 GET 请求成功的情况下可以获取到 mycar.html 的上下文信息。

Promise

在了解过回调(callbacks)和异步(Asyncchronous)之后,回归正题,Axios 主要是基于 Promise 来进行构建,那么 Promise 在通过一开始所介绍的 “故事” 内,我们知道,生产者代码需要一些时间,而消费者代码是可以得到反馈的。

Promise Object

1
2
3
4
5
6
7
8
9
10
11
12
let myPromise = new Promise(function(myResolve, myReject) {  
// "Producing Code" (May take some time)

myResolve(); // when successful
myReject(); // when error
});

// "Consuming Code" (Must wait for a fulfilled Promise)
myPromise.then(
function(value) { /* code if successful */ },
function(error) { /* code if some error */ }
);

JavaScript Promise Object 包含了上述中生产者带么和消费者代码的实现,当之后 Promise 执行时,他会调用两个回调方法,如果时结果值那么就 successful,否则 error,这也对应着 Promise Object 所支持的两个属性,状态和结果。

.then()

最终,Promise 会通过 .then() 来返回成功和失败的回调函数,他的概念主要还是 Promise Object 所支持的两个属性,更加详细的可以参考下 MDN 的 Promise.prototype.then() - JavaScript | MDN (mozilla.org) 详细了解具体原理。

最后总结一点是,如果 Promise 返回了一个值,那么 then 将会成为接受(accept)状态,没返回任何值,then 同样会返回接收状态,并将接受状态的回调参数设置为 undefined

假设抛出一个错误,那么 then 也会返回一个拒绝状态,并将错误信息回调到参数值中。但如果是一个接受的 Promise,那么 then 就会将状态设置为 fulfilled,反之则是 rejected

如果遇到一个未定状态(pending),那么 then 所返回的 Promise 也会是未定的,在 W3 中,同样给了我们一个非常简单的例子供我们进行理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Promise</h2>

<p id="demo"></p>

<script>
function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}

let myPromise = new Promise(function(myResolve, myReject) {
let x = 0;

// some code (try to change x to 5)

if (x == 0) {
myResolve("OK");
} else {
myReject("Error");
}
});

myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
</script>

</body>
</html>

在上述的 Code 中,同样的有两个最后的状态进行输出,一个是成功的而另一个则是错误的状态信息进行输出,通过 .then() 使得我们可以处理异步中的错误,以及成功返回的信息。

Async/Await

Async

在 async 和 await 还未出现之前,异步编程通常会苦恼当前的开发人员,但在 ECMAScript 2017 中,async/await 通过 promises 使得将异步的编写更加容易和方便,同时增加的阅读性。

我们可以将 async 和 await 拆分下来(虽然 await 离开了 async 些许并没有什么作用),async 可以理解为 promise 中的生产者代码:

1
2
3
4
async function hello() {
console.log("Hello,world!")
}
hello();

上述代码中的 async 同等与传统方法中的 function,之后,我们还需要配合 await 来进行使用。

Await

而之后的 await,他实际上就是 .then,只可以和 async 搭配进行使用,基于 promise 的函数之前。它会暂停代码在该行上,直到 promise 完成,然后返回结果值。在暂停的同时,其他正在等待执行的代码就有机会执行了:

1
2
3
4
5
async function hello() {
return greeting = await Promise.resolve("Hello");
};

hello().then(alert);

顾名思义,也就是在 await 的同时,他会来进行回调的调用,来代替之前我们之前直接一个函数来进行回调,同时他也完成了 then 的部分工作,使得 then 会减少使用。

⬅️ Go back